/*****************************************************************************
*    Ali Corp. All Rights Reserved. 2002 Copyright (C)
*
*    File:    bootloader.c
*
*    Description:    This file contains all globe micros and functions declare
*                    of Flash boot loader.
*    History:
*           Date            Athor        Version          Reason
*       ============    =============   =========   =================
*   1.  Oct.28.2003     Justin Wu       Ver 0.1    Create file.
 *  2.  2006.5.16       Justin Wu       Ver 0.2    STO chunk support & clean up.
*****************************************************************************/
#include <sys_config.h>
#include <sys_parameters.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <api/libchunk/chunk.h>
#include <bus/sci/sci.h>
#include <bus/flash/flash.h>
#include <hal/hal_gpio.h>
#include <hal/hal_mem.h>
#include <hld/pan/pan_dev.h>
#include <hld/pan/pan.h>
#include <bus/i2c/i2c.h>

#define _OTA_E_
#define SYS_CPU_CLOCK_FPGA 13000000
#define US_TICKS       (sys_ic_get_cpu_clock()*1000000 / 2000000)// (SYS_CPU_CLOCK / 2000000)
#define WAIT_300MS      (300000 * US_TICKS)
#define WAIT_150MS      (150000 * US_TICKS) //add for fast boot up
#define WAIT_500MS		(500000 * US_TICKS)
#define WAIT_5MS        (5000   * US_TICKS)

#undef FIXED_PRINTF
//#define FIXED_PRINTF     libc_printf
#define FIXED_PRINTF(...)     do{}while(0)
/* Calcuate InternalBufferSize for 7-zip */
#define LZMA_BASE_SIZE  1846
#define LZMA_LIT_SIZE   768
#define BUFFER_SIZE     ((LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (0 + 2))) * sizeof(UINT16))

#define GET_FILE_SIZE(p)  ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
#define WRITE_UINT8(uAddr, bVal)    do {*(volatile UINT8 *)(uAddr) = (bVal);} while(0)

#ifdef __mips16
#define SDBBP()		asm volatile(".half 0xe801; \
								  nop")
#else
#define SDBBP()		asm volatile(".word	0x7000003f; \
								  nop");
#endif

#ifdef C3041
#define	__ATTRIBUTE_BOOT_ __attribute__((section(".boot")))
__ATTRIBUTE_BOOT_ UINT32 stb_gpio = 8;
__ATTRIBUTE_BOOT_ UINT32 clk_gpio = 37;
__ATTRIBUTE_BOOT_ UINT32 data_gpio = 9;
#endif

#ifndef FP_CS_GPIO_NUM
#define FP_CS_GPIO_NUM 95
#endif


static struct pan_hw_info pan_hw_info =
{
	0,				/* type_kb : 2; Key board (array) type */
	1,				/* type_scan : 1; 0: Slot scan, 1: Shadow scan */
	1,				/* type_key: 1; Key exit or not */
	1,				/* type_irp: 3; 0: not IRP, 1: NEC, 2: LAB */
	0,				/* type_mcu: 1; MCU exit or not */
	4,				/* num_com: 4; Number of com PIN, 0 to 8 */
	1,				/* Position of colon flag, 0 to 7 */
	1,				/* num_scan: 2; Number of scan PIN, 0 to 2 */
	0,				/* rsvd_bits:6; Reserved bits */
	0,              /* rsvd byte for align pan_info */
	{0, HAL_GPIO_O_DIR, 127},		/* LATCH PIN */
	{0, HAL_GPIO_O_DIR, 	127},		/* CLOCK PIN */
	{1, HAL_GPIO_O_DIR, 	127},		/* DATA PIN */
	{{0, HAL_GPIO_I_DIR, 	127},		/* SCAN1 PIN */
	{0, HAL_GPIO_I_DIR, 127}},		/* SCAN2 PIN */
	{{0, HAL_GPIO_O_DIR, 	127},		/* COM1 PIN */
	{0, HAL_GPIO_O_DIR, 	127},		/* COM2 PIN */
	{0, HAL_GPIO_O_DIR, 	127},		/* COM3 PIN */
	{0, HAL_GPIO_O_DIR, 	127},		/* COM4 PIN */
	{0, HAL_GPIO_O_DIR, 127},		/* COM5 PIN */
	{0, HAL_GPIO_O_DIR, 127},		/* COM6 PIN */
	{0, HAL_GPIO_O_DIR, 127},		/* COM7 PIN */
	{0, HAL_GPIO_O_DIR, 127}},		/* COM8 PIN */
	{{0, HAL_GPIO_O_DIR, 	127},		/* POWER PIN */
	{1, HAL_GPIO_O_DIR, 	127},		/* LOCK PIN */
	{0, HAL_GPIO_O_DIR, 127},		/* Extend function LBD */
	{0, HAL_GPIO_O_DIR, 127}},		/* Extend function LBD */
    {0, HAL_GPIO_O_DIR, 127},       /* rsvd extend function LBD */        
	300,							/* Intv repeat first */
	250,							/* Intv repeat */
	350,							    /* Intv release, 0: disable release key */
	NULL,	 	 	 	 	 	 	/* hook_scan() callback */
	NULL,	 	 	 	 	 	 	/* hook_show() callback */
};
#define bitmap_list				NULL
#define bitmap_list_num		0
struct pan_configuration pan_config = {&pan_hw_info, bitmap_list_num, bitmap_list};
struct pan_device *panel_dev;

#ifdef _BOARD_DB_M3805_01V01_
#define SDA_POSTION 30
#define SCL_POSTION 9
#else
#define SDA_POSTION 9
#define SCL_POSTION 31
#endif


struct sto_device *flash_dev;

UINT16 g_blogo_format = 0;  /* Bootloader logo parameters */
UINT8  g_second_loader = 0;
UINT8  g_crc_bad;

extern int gzip_decompress(UINT8 *, UINT8 *, UINT8 *);
extern int un7zip(UINT8 *, UINT8 *, UINT8 *);
extern int unlzo(UINT8 *, UINT8 *, UINT8 *);   //add for fast boot up

#define SEE_CODE  1
#define MAIN_CODE 0
#define MAIN_ENTRY 0x80000200
#define SEE_TEMP 0xa1a00200
#define MAIN_TEMP 0x81e80000

static UINT32 g_ota_offset = 0;
static UINT8 find_second_loader()
{
#ifdef _OTA_E_
#define C_SECTOR_SIZE   0x10000
    UINT8 *buffer;
    UINT32 data_id;
    UINT32 data_len;
    UINT32 data_off;
    UINT32 data_crc;
    UINT32 crc;
    UINT32 pointer = 0;

    UINT8 bSecondOta = 0;

    while(pointer < flash_dev->totol_size)
    {
        data_id  = sto_fetch_long((UINT32)pointer + CHUNK_ID);
        data_len = sto_fetch_long((UINT32)pointer + CHUNK_LENGTH);
        data_off = sto_fetch_long((UINT32)pointer + CHUNK_OFFSET);
        data_crc = sto_fetch_long((UINT32)pointer + CHUNK_CRC);
        if(data_len && (data_len < data_off) && (data_crc != NO_CRC) && ((data_id & CHUNKID_SECLOADER_MASK) == CHUNKID_SECLOADER))
        {
            buffer = (UINT8 *)MALLOC(data_len);
        	if(buffer != NULL)
        	{
    		    sto_get_data(flash_dev, buffer, pointer + 16, data_len);
                crc = MG_Table_Driven_CRC(0xFFFFFFFF, buffer, data_len);
                FREE(buffer);
                if(data_crc == crc)
                {
                    g_ota_offset = pointer;
                    bSecondOta = 1;
                    break;
                }
        	}
        }
	    pointer += C_SECTOR_SIZE;
    }

    //verify the second loader.
    if (bSecondOta)
    {
        pointer = g_ota_offset;
        do
        {
            data_id  = sto_fetch_long((UINT32)pointer + CHUNK_ID);
            data_len = sto_fetch_long((UINT32)pointer + CHUNK_LENGTH);
            data_off = sto_fetch_long((UINT32)pointer + CHUNK_OFFSET);
            data_crc = sto_fetch_long((UINT32)pointer + CHUNK_CRC);

            /*
            if (pointer != 0)
            {
                if ((data_id >> 16) & 0xFF + (data_id >> 24) & 0xFF != 0xFF)
                {
                    bSecondOta = 0;
                    break;
                }
            }
            */
    		FIXED_PRINTF("2.6!\n");
            if (data_off > flash_dev->totol_size)
            {
                FIXED_PRINTF("@pointer[%08X] id[%08X] data_off[%08X] > flash size\n", \
                      pointer, data_id, data_off);
                bSecondOta = 0;
                break;
            }
            if ((data_off != 0) && (data_len > data_off))
            {
                FIXED_PRINTF("@pointer[%08X] id[%08X] data_len[%08X] > data_off[%08X]\n", \
                      pointer, data_id, data_len, data_off);
                bSecondOta = 0;
                break;
            }
    	    if (data_crc != NO_CRC)
            {
    			if ((buffer = (UINT8 *)MALLOC(data_len)) == NULL)
                    ASSERT(0);
                sto_get_data(flash_dev, buffer, pointer + 16, data_len);
                crc = MG_Table_Driven_CRC(0xFFFFFFFF, buffer, data_len);
                FREE(buffer);
    			FIXED_PRINTF("2.7!\n");
                if (data_crc != crc)
                {
                    FIXED_PRINTF("@pointer[%08X] id[%08X] crc[%08X] != data_crc[%08X]\n", \
                        pointer, data_id, crc, data_crc);
                    bSecondOta = 0;
                    break;
                }
            }
            pointer += data_off;
            if (pointer + CHUNK_HEADER_SIZE > flash_dev->totol_size)
            {
                FIXED_PRINTF("@pointer[%08X] no space for header\n", pointer);
                bSecondOta = 0;
                break;
            }

        } while (data_off);
    }
    if (0 == bSecondOta)
        g_ota_offset = 0;
    return bSecondOta;
#endif
    return 0;
}


UINT8 check_program(void)
{
    UINT32 i;
    UINT8 *buffer;
    UINT32 data_id;
    UINT32 data_len;
    UINT32 data_off;
    UINT32 data_crc;
    UINT32 crc;
    UINT32 pointer = 0;
	FIXED_PRINTF("check_program!\n");
    g_second_loader = find_second_loader();
    do
    {
        data_id  = sto_fetch_long((UINT32)pointer + CHUNK_ID);
        data_len = sto_fetch_long((UINT32)pointer + CHUNK_LENGTH);
        data_off = sto_fetch_long((UINT32)pointer + CHUNK_OFFSET);
        data_crc = sto_fetch_long((UINT32)pointer + CHUNK_CRC);

        if (pointer != 0)
        {
            if (((data_id >> 16) & 0xFF) + ((data_id >> 24) & 0xFF) != 0xFF)
                return 1;
        }
        if (data_off > flash_dev->totol_size)
        {
            FIXED_PRINTF("@pointer[%08X] id[%08X] data_off[%08X] > flash size\n", \
                  pointer, data_id, data_off);
            return 2;
        }
        if ((data_off != 0) && (data_len > data_off))
        {
            FIXED_PRINTF("@pointer[%08X] id[%08X] data_len[%08X] > data_off[%08X]\n", \
                  pointer, data_id, data_len, data_off);
            return 3;
        }
	    if (data_crc != NO_CRC)
        {
			if ((buffer = (UINT8 *)MALLOC(data_len)) == NULL)
                ASSERT(0);
            sto_get_data(flash_dev, buffer, pointer + 16, data_len);
            crc = MG_Table_Driven_CRC(0xFFFFFFFF, buffer, data_len);
            FREE(buffer);
            if (data_crc != crc)
            {
                FIXED_PRINTF("@pointer[%08X] id[%08X] crc[%08X] != data_crc[%08X]\n", \
                    pointer, data_id, crc, data_crc);
                return 4;
            }
        }
        pointer += data_off;
        if (pointer + CHUNK_HEADER_SIZE > flash_dev->totol_size)
        {
            FIXED_PRINTF("@pointer[%08X] no space for header\n", pointer);
            return 5;
        }

    } while (data_off);

    return 0;
}

extern UINT32 g_see_entry;
extern UINT32 g_see_length;
extern UINT32 g_see_ram_base;

UINT8 *expand(UINT32 offset, int unzip(UINT8 *, UINT8 *, UINT8 *),UINT32 type)
{
    UINT8 *entry;
    UINT8 *buffer;
    UINT32 code_len;
    UINT8 *codestart;

    //add for fast boot up
    UINT8 ret = 0;
    UINT8* flag;

    codestart = (UINT8 *)sto_fetch_long((UINT32)offset + CHUNK_CODESTART);
    entry = (UINT8 *)sto_fetch_long((UINT32)offset + CHUNK_ENTRY);
    if (codestart == 0 || codestart == (UINT8 *)0xFFFFFFFF)
    {
		if(type == MAIN_CODE)	codestart = (UINT8 *)MAIN_ENTRY;
		if(type == SEE_CODE)    codestart = (UINT8 *)SEE_TEMP;
    }
    if (entry == 0 || entry == (UINT8 *)0xFFFFFFFF)
        entry = codestart;
    /* Copy compressed code into DRAM */
    code_len = sto_fetch_long((UINT32)offset + CHUNK_LENGTH);
	if(type == MAIN_CODE)
    	sto_get_data(flash_dev, (void *)(MAIN_TEMP - code_len), offset + CHUNK_HEADER_SIZE, code_len);
	if(type == SEE_CODE)
		// 2*chunk_head_size because there two chunk before see_code
		sto_get_data(flash_dev, (void *)(MAIN_TEMP - code_len), offset + CHUNK_HEADER_SIZE, code_len);
    buffer = MALLOC(BUFFER_SIZE);
    if (buffer == NULL)
    {
        FIXED_PRINTF("Boot loader: No decompress buffer!\n");
        entry = 0;
    }
    else
    {
                //add for fast boot up
                flag= (UINT8 *)(MAIN_TEMP - code_len);

		if(type == MAIN_CODE)
		{
                    //change for fast boot up, lzma must have 4 bytes: 0x6c 0x00 0x00 0x80 
                    if(flag[0] == 0x6c && flag[1] == 0x0 && flag[2] == 0x0 && flag[3] == 0x80 )
                        ret = unzip((void *)(MAIN_TEMP - code_len), codestart, buffer);    
                    else
                        ret = unlzo((void *)(MAIN_TEMP - code_len), codestart, buffer);
                    
                    if (ret != 0)
                    {
                        FIXED_PRINTF("Boot loader: Decompress error!\n");
                        entry = 0;
                    }
		}
		if(type == SEE_CODE)
		{
                    //change for fast boot up, lzma must have 4 bytes: 0x6c 0x00 0x00 0x80 
                    if(flag[0] == 0x6c && flag[1] == 0x0 && flag[2] == 0x0 && flag[3] == 0x80 )
                        ret = unzip((void *)(MAIN_TEMP - code_len), codestart, buffer);    
                    else
                        ret = unlzo((void *)(MAIN_TEMP - code_len), codestart, buffer);
            
                    if (ret != 0)
                    {
                        FIXED_PRINTF("SEE Boot loader: Decompress error!\n");
                        entry = 0;
                    }
                    else
                    {
                        *(UINT32 *)((UINT32)(&g_see_length)|0xa0000000) = *(UINT32*)buffer;
                    }
		}
        FREE(buffer);
    }

    return entry;
}

static void pin_mux_set(UINT32 value, UINT8 start_bit, UINT8 bit_num)
{
    UINT32 reg_tmp;
    UINT32 mask = 0, i, tmp;

    reg_tmp = *((volatile UINT32 *)0xb8000028);
    tmp = 1;
    for(i = 0; i < bit_num; i++)
    {
        tmp <<= 1;
        tmp |= 1;
    }
    mask = ~(tmp<<start_bit);

    reg_tmp &= mask;
    reg_tmp |= (value<<start_bit);

    *((volatile UINT32 *)0xb8000028) = reg_tmp;
}

/*
ota data backup header:
|backup start flag  |backup end flag|
|  16bytes mark   |     4bytes          |
backup address: 0xbfd20000
*/
#define UN7ZIP_BUFF_ADDR    0xA0460000;
#define UN7ZIP_SWAP_ADDR    0xA0400000
#define BACKUP_START_FLAG   0x55aa5a5a

#define OTA_BACKUP_OFFSET 16

UINT8 b_end_mark[16] = {0x65,0x72,0x6F,0x74,0x73,0x65,0x72,0x5F,0x67,0x6F,0x72,0x70,0x5F,0x61,0x74,0x6F};/* erotser_gorp_ato*/

UINT32 ota_get_restore_addr()
{
    UINT32 f_addr;
    UINT32 buf;

    f_addr = SYS_FLASH_BASE_ADDR + flash_dev->totol_size;

    // search ota retore addr from end to start
    while(f_addr > SYS_FLASH_BASE_ADDR)
    {
        // find sector ahead
        f_addr -= 64*1024;
        // align to 64k
        //f_addr = f_addr - f_addr%(64*1024);
        f_addr &= 0xffff0000;

        if(*(UINT32 *)(f_addr+OTA_BACKUP_OFFSET) == BACKUP_START_FLAG)
            return f_addr;
    }

    return 0xFFFFFFFF;
}

INT32  ota_prog_restore()
{
    UINT32 write_size,param;
    UINT32 offset,code_size,ota_data_size,check_size,check_crc;
    UINT8 i = 0;
    UINT8 buf[16];
    UINT8 *un7zip_buff;
    UINT8 *swap_buff;
    UINT8 *block_addr;
    UINT8 *f_block_addr;
    UINT8 *userdb_addr;
    UINT32 b_addr;
    UINT32 chid = 0x04FB0100;

    /* check if restore data exist */
    b_addr = ota_get_restore_addr();
    if (b_addr == 0xFFFFFFFF)
        return -1;
    MEMCPY(buf,(UINT8*)b_addr,16);
    if(MEMCMP(b_end_mark,buf,16) == 0)/* found restore data */
    {
        un7zip_buff =(UINT8 *)UN7ZIP_BUFF_ADDR;
        swap_buff = (UINT8 *)UN7ZIP_SWAP_ADDR;
        /* de-compress restore data */
        if(un7zip((UINT8*)(b_addr+16+4),un7zip_buff,swap_buff) != 0)
        {
            FIXED_PRINTF("un7zip restore data failed.\n");
#ifdef PANEL_DISPLAY
            pan_display(panel_dev, "E001", 4);
#endif
            return -1;
        }
        /* check CRC */
        ota_data_size = *((UINT32*)swap_buff);
        FIXED_PRINTF("Check CRC...\n");

        MG_Setup_CRC_Table();
        offset = 0;
        block_addr = un7zip_buff;
        code_size = ota_data_size;
        FIXED_PRINTF("block_addr = 0x%8x \n",block_addr);
        FIXED_PRINTF("code_size = 0x%8x \n",code_size);
        do{
            block_addr += offset;
            check_size = (block_addr[4]<<24)
                        +(block_addr[5]<<16)
                        +(block_addr[6]<<8)
                        +block_addr[7];

            offset =        (block_addr[8]<<24)
                        +(block_addr[9]<<16)
                        +(block_addr[10]<<8)
                        +block_addr[11];

            if(offset > code_size)
            {
                FIXED_PRINTF("ERROR : size NOT enough !\n");
#ifdef PANEL_DISPLAY
                pan_display(panel_dev, "E002", 4);
#endif
                return -1;
            }
            code_size -= offset;


            check_crc = (block_addr[12]<<24)
                        +(block_addr[13]<<16)
                        +(block_addr[14]<<8)
                        +block_addr[15];
            FIXED_PRINTF("crc = 0x%8x \n",check_crc);
            if(check_crc != NO_CRC)
            {
                if(check_crc != (UINT32)MG_Table_Driven_CRC(0xFFFFFFFF, block_addr + 0x10, check_size))
                {
                    FIXED_PRINTF("ERROR : CRC error !\n");
#ifdef PANEL_DISPLAY
                    pan_display(panel_dev, "E003", 4);
#endif
                    return -1;
                }
            }
        }while(offset!=0&&code_size>0);
        /* if CRC is OK, then start burning flash */
        ota_data_size = b_addr - SYS_FLASH_BASE_ADDR;
        code_size = ota_data_size;
        block_addr = un7zip_buff;
        f_block_addr = 0;
        if (sto_lseek(flash_dev, 0, STO_LSEEK_SET) != 0)
        {
            return -1;
        }
        if (sto_read(flash_dev, swap_buff, 64*1024) != 64*1024)
        {
            FIXED_PRINTF("ERROR: sto_read failed!\n");
            return -1;
        }

        /* find position of userdb */
        chunk_init((UINT32)un7zip_buff,0x200000);
        userdb_addr = chunk_goto(&chid, 0xFFFFFFFF, 1) ;
        code_size = (userdb_addr-un7zip_buff);
        code_size += 0x80; /* user db chunk header */

        offset =    (swap_buff[8]<<24)
                    +(swap_buff[9]<<16)
                    +(swap_buff[10]<<8)
                    +swap_buff[11];
        f_block_addr += offset; //skip bootloader of flash address
        code_size -= offset;
        ota_data_size -= offset;
        block_addr += offset; //skip bootloader of sdram address
        while(code_size)
        {
            write_size = (code_size < 64*1024) ? code_size : 64*1024;

            /* Uper 22 bits of MSB is start offset based on SYS_FLASH_BASE_ADDR */
            //param =(UINT32) f_block_addr;
            //param = param << 10;
            /* Lower 10 bits of LSB is length in K bytes*/
           // param += (64*1024) >> 10;
            //if(sto_io_control(flash_dev, STO_DRIVER_SECTOR_ERASE, param) != SUCCESS)
             UINT32 tmp_param[2];
						tmp_param[0] = (UINT32) f_block_addr;
						tmp_param[1] = (64*1024)>>10;
						param= (UINT32)tmp_param;

						if(sto_io_control(flash_dev, STO_DRIVER_SECTOR_ERASE_EXT, param) != SUCCESS)//Summic add for check the >=4M Flash
             {
                FIXED_PRINTF("ERROR: erase flash memory failed!\n");
                return -1;
            }
            if (sto_lseek(flash_dev,(INT32)f_block_addr,STO_LSEEK_SET) != (INT32)f_block_addr)
            {
                FIXED_PRINTF("ERROR: sto_lseek failed!\n");
                return -1;
            }
            if(sto_write(flash_dev, block_addr, write_size)!=write_size)
            {
                FIXED_PRINTF("ERROR: sto_write failed!\n");
                return -1;
            }
            f_block_addr +=(64*1024);
            block_addr +=write_size;
            code_size -= write_size;
#ifdef PANEL_DISPLAY
//          sprintf(buf,"%x",((ota_data_size-code_size)*100/ota_data_size));
            if(i%2 == 0)
                pan_display(panel_dev, "_-_-", 4);
            else
                pan_display(panel_dev, "-_-_", 4);
            i++;
#endif
        }
        return 0;

    }
    else
    {
#ifdef PANEL_DISPLAY
        pan_display(panel_dev, "Err ", 4);
#endif
    }
    return -1;
}

void clean_restore_data()
{
    UINT32 param;
    UINT32 b_addr;

    b_addr = ota_get_restore_addr();
    if(b_addr != 0xFFFFFFFF)
    {
#ifdef PANEL_DISPLAY
        pan_display(panel_dev, "CLr ", 4);
#endif
        /* Uper 22 bits of MSB is start offset based on SYS_FLASH_BASE_ADDR */
       // param = b_addr - SYS_FLASH_BASE_ADDR;
        //param = param << 10;
        /* Lower 10 bits of LSB is length in K bytes*/
       // param += (flash_dev->totol_size-(b_addr - SYS_FLASH_BASE_ADDR)) >> 10;
        //if(sto_io_control(flash_dev, STO_DRIVER_SECTOR_ERASE, param) != SUCCESS)
       UINT32 tmp_param[2];
			tmp_param[0] = b_addr - SYS_FLASH_BASE_ADDR;
			tmp_param[1] = (flash_dev->totol_size-(b_addr - SYS_FLASH_BASE_ADDR))>>10;
			param= (UINT32)tmp_param;
        if(sto_io_control(flash_dev, STO_DRIVER_SECTOR_ERASE_EXT, param) != SUCCESS)//Summic add for check the >=4M Flash
        {
            FIXED_PRINTF("ERROR: clean restore data  failed!\n");
            return;
        }
    }
}

static void set_os_config()
{
    struct os_config *ptr = (struct os_config *)0xa00001e0;

    ptr->task_num = 0;
    ptr->sema_num = 0;
    ptr->flg_num = 0;
    ptr->mbf_num = 0;
    ptr->mutex_num = 0;
    ptr->parity_value = ptr->task_num + ptr->sema_num + ptr->flg_num + ptr->mbf_num + ptr->mutex_num;
}

static void bl_GPIO_init()
{
	#ifdef _BOARD_DB_M3805_01V01_  //01v02
	static UINT32 data[3] = {0x40000200, 0x0, 0x0};
	#else
	static UINT32 data[3] = {0x80000200, 0x0, 0x0};
	#endif
	UINT32 reg_addr[] = 
    {
         GPIO_REG, GPIOA_REG, GPIOB_REG, //GPIOC_REG, GPIOD_REG, 
    };
    UINT32 i, j, value;

    // disable all GPIO
    for(i=0; i<sizeof(reg_addr)/sizeof(reg_addr[0]); i++)
    {
		value = data[i];
        *((volatile unsigned long *)reg_addr[i]) = value;
    }
}
static void bl_uart_init()
{
#ifndef ENABLE_EROM
	  libc_printf_uart_id_set(0);
      sci_16550uart_attach(1);    /* Use just 1 UART for RS232 */
      sci_mode_set(SCI_FOR_RS232, 115200, SCI_PARITY_EVEN);
      FIXED_PRINTF("APP  init!\n");
#endif
}


static void bl_panel_init()
{
	UINT32 data;
#ifdef PANEL_DISPLAY
	FIXED_PRINTF("bl_panel_init!\n");
	/* Init front panel and IR */
    data = *((unsigned char *)0xb8000088);
    data |= 0x9;
	*((unsigned char *)0xb8000088) = data;

	i2c_scb_attach(1);
	i2c_gpio_attach(1);
	i2c_gpio_set(0, SDA_POSTION, SCL_POSTION);		// SCART/panel
	extern void pan_ch455_id_set(struct pan_device *dev, UINT32 id);
	pan_ch455_attach(&pan_config);
	panel_dev = (struct pan_device *)dev_get_by_id(HLD_DEV_TYPE_PAN, 0);
	pan_ch455_id_set(panel_dev,I2C_TYPE_GPIO);

    pan_open(panel_dev);
    pan_display(panel_dev, " ON ", 4);
#endif
}
static void bl_flash_init()
{
	UINT32 flash_speed;

	FIXED_PRINTF("bl_flash_init!\n");
	*((unsigned long *)0xb802e098) |=  0xc6000000;  //for flash can read 4M
#ifndef ENABLE_SERIAL_FLASH
    flash_info_pl_init();
    sto_local_flash_attach(NULL);
#else
    flash_info_sl_init();
    sto_local_sflash_attach(NULL);
#endif
    flash_dev = (struct sto_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_STO);
    if (flash_dev == NULL)
    {
        FIXED_PRINTF("Can't find FLASH device!\n");
    }
    sto_open(flash_dev);
    sto_chunk_init(0, flash_dev->totol_size);
    sto_get_data(flash_dev, &flash_speed, HW_SET_FLASHSPEED, 1);
    flash_speed &= 0x3F;
    if (flash_speed == 0)
        flash_speed = HW_FLASH_DEFSPEED;
    HAL_ROM_MODE_SET(flash_speed, 0, 1, 0);
}
static bl_verify_sw()
{

    FIXED_PRINTF("bl_verify_sw\n");
    MG_Setup_CRC_Table();//Rs232 upgrade must use
    g_crc_bad = check_program();
	if(g_crc_bad)
		FIXED_PRINTF("crc error!\n");
}

void AppInit(void)
{
    UINT8  ch, *t1, *t2, i;
    UINT32 boot_tick;
    UINT32 chid;
    UINT32 offset,offset1=0,offset2=0;
    UINT8 *main_entry,*see_entry,*see_ram_address;
    UINT8  boot_type;
    UINT32 boot_code,tmp,data;
#ifdef CI_PLUS_SUPPORT
	UINT32 maincode_len, maincode_addr, len_left;
	UINT8 maincode_left[32];
#endif

    boot_code = *(UINT32 *)(0xA0000110);
    /* Cold bootup */
    boot_type = *(UINT8 *)(SYS_FLASH_BASE_ADDR + HW_SET_BOOTTYPE);
    if ((boot_type & BOOT_TYPE_MASK) && boot_code == 0xdead3bee)
    {
        /* If cold bootup and enter standby enabled, enter standby */
        sys_ic_enter_standby(0, 0);
    }

    /* Initialize */
	bl_GPIO_init();
	bl_uart_init();
	bl_panel_init();
	bl_flash_init();
	bl_verify_sw();

    if (g_crc_bad == 0 || g_second_loader == 1)
    {

#ifdef _OTA_E_
        if(g_second_loader)
        {
            chid = CHUNKID_SECLOADER;
            offset2 = g_ota_offset;
        }
        else
#endif

	    if (g_crc_bad == 0)
	    {
	        /* If dynamic application load enable, try load this application */
	        if (boot_code == 0xdead2bee)
	        {
	            chid = *((UINT32 *)0xA0000114);
	            offset = sto_chunk_goto(&chid, *((UINT32 *)0xA0000118), 1);
	        }
	        else
	        {
	            chid = CHUNKID_MAINCODE;
                offset2 = sto_chunk_goto(&chid, CHUNKID_MAINCODE_MASK, 1);	
	        }
	    }
        main_entry = 0;
        if (offset2 != 0)
        {
          main_entry = expand(offset2, un7zip,MAIN_CODE);
        }

        if (main_entry != 0)
        {
            boot_tick = read_tsc();
            do
            {
                if (sci_read_tm(SCI_FOR_RS232, &ch, 5) == SUCCESS && ch == 'c')
                    break;
                else
                    ch = 0;
            }
            while (read_tsc() - boot_tick < WAIT_150MS);
            //change for fast boot up
            //while (read_tsc() - boot_tick < WAIT_300MS);
            
            if (ch != 'c')
            {
				set_os_config();
				FIXED_PRINTF("success!\n");
                osal_cache_flush_all();
                exec(main_entry);
            }
        }
    }
    else
    {
        FIXED_PRINTF("Boot loader: CRC bad%d! \n", g_crc_bad);
        if(ota_prog_restore() == 0)
        {
            //boot_logo();
            /* re-check CRC and jump to maincode */
            chid = CHUNKID_MAINCODE;
            offset = sto_chunk_goto(&chid, CHUNKID_MAINCODE_MASK, 1);
             main_entry = 0;
            if (offset != 0)
            {
                main_entry = expand(offset, un7zip,MAIN_CODE);
            }
            if (main_entry != 0)
            {
                clean_restore_data();/* clean backup data while restore ok */
				set_os_config();
				FIXED_PRINTF("5!\n");
                osal_cache_flush_all();
                exec(main_entry);
            }
        }
    }
    lib_ash_shell();
}
